/**
 * 
 */
package com.bloomingstars.sqm;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ConnectException;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Properties;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.bloomingstars.sqm.orm.SqmReadingEntity;
import com.bloomingstars.sqm.orm.SqmReadingEntityDao;
import com.bloomingstars.sqm.sgoudelis.poller.SQMLE;
import com.bloomingstars.sqm.sgoudelis.poller.SQMLEPasswordException;
import com.bloomingstars.sqm.sgoudelis.poller.SQMLEPoller;

/**
 * @author Emmanuele Sordini
 *
 */
public class SqmLEReader {

    private static final Logger logger = LogManager.getLogger(SQMLEPoller.class);
    private static int pollingFrequency = 30;
    private static boolean calcCsf = false;
    private static boolean archiveToDb = false;
    private static DateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss z");   

    public static void main(String[] args) {
        SQMLE sqmle;
        String configFile = "sqmle-reader.properties";
        SqmReadingEntityDao dao = new SqmReadingEntityDao(SqmReadingEntity.class);

        System.out.println(System.getProperty("java.class.path"));
        
        Properties settings = new Properties();
        
        try {
            settings.load(new FileInputStream(configFile));
        } catch (NullPointerException settingsEx) {
            logger.error("Exception raised while reading configuration properties: " + settingsEx);
            logger.error("Error message: " + settingsEx.getMessage());
            System.exit(1);
        } catch (FileNotFoundException settingsEx) {
            logger.error("Could not find properties file: " + configFile);
            logger.error("Error message: " + settingsEx.getMessage());            
            System.exit(1);
        } catch (IOException settingsEx) {
            logger.error("Exception raised while reading configuration properties: " + settingsEx);
            logger.error("Error message: " + settingsEx.getMessage());
            System.exit(1);            
        }

        setPollingFrequency(settings);  
        setCalcCsf(settings);        
        setArchiveToDb(settings);

        String fileName = settings.getProperty(SqmConfigParam.FILE_NAME.getName(), "SqmReadings.csv");
        
        int timeSpan = 86400; 
        try {
            String s = settings.getProperty(SqmConfigParam.LOGGING_TIMESPAN.getName());
            if (s != null) {
                timeSpan = Integer.parseInt(s);
            } else {
                logger.warn("Logging timespan value not set in config file. Using default");
            }
        } catch (NumberFormatException ex) {
            logger.warn("Error reading logging timespan value: incorrect format. Using default.");
        }
        SqmReadingManager manager = new SqmReadingManager(timeSpan/pollingFrequency, fileName);

        try {
            manager.readFile();
        } catch (IOException e1) {
            logger.error("Error reading CSV file. Resetting content...");
        }
                
        while (true) {
            String deviceHost = settings.getProperty("host");
            int devicePort = Integer.parseInt(settings.getProperty("port"));
            String devicePassword = settings.getProperty("password");
            
            sqmle = new SQMLE(deviceHost, devicePort, devicePassword);
            try {
                sqmle.getReadings();
            } catch (UnknownHostException e) {
                System.out.println(String.format("Could not resolve host %s:%s (%s)", deviceHost, devicePort, e.getMessage()));
            } catch (ConnectException e) {
                System.out.println(String.format("Could not connect to SQM-LE device %s:%s (%s)", deviceHost, devicePort, e.getMessage()));
            } catch (SQMLEPasswordException e) {
                System.out.println(String.format("Could not send password to SQM-LE device %s:%s (%s)", deviceHost, devicePort, e.getMessage()));
            } catch (Exception e) {
                logger.error("Exception raised getting SQM reading");
                logger.error(e);
                logger.error(e.getMessage());
            }
            
            double csf = -1.0;
            if (calcCsf && manager.canCalcCsf()) {
                csf = manager.calcCsf();
            }
            
            logger.info("Date: " + format.format(new Date()) + " " + sqmle.getMagPerSqAS() + " mag/arcsec^2 " +
                        " Period count: " + sqmle.getPeriodCount() + " Period: " + sqmle.getPeriodSeconds() + 
                        " s Temp: " + sqmle.getTemperature() + " degs C CSF: " + (csf==-1.0?"N/A":csf) );
            
//            System.out.println("serial: " + sqmle.getSerialNumber() + " "
//                    + sqmle.getMagPerSqAS() + "mag/arcsec^2 " + sqmle.getFrequency()
//                    + "Hz " + sqmle.getPeriodCount() + "c " + sqmle.getPeriodSeconds()
//                    + "s " + sqmle.getTemperature() + "C");
            
            Calendar cal = Calendar.getInstance();
            SqmReadingRecord record = new SqmReadingRecord(cal, sqmle.getMagPerSqAS(), sqmle.getTemperature());
            
            manager.addReading(record);
            
            try {
                manager.writeFile();
            } catch (IOException e1) {
                logger.error("Error writing readings table to file. Skipping this time.");
            }
     
            if (archiveToDb) {
                try {
                    SqmReadingEntity sre = new SqmReadingEntity();
                    sre.setTimeUt(cal.getTimeInMillis());
                    sre.setReading(sqmle.getMagPerSqAS());
                    sre.setTemperature(sqmle.getTemperature());
                    
                    dao.create(sre);
                } catch (Throwable ex) {
                    logger.error("Exception raised saving SQM reading to database");
                    logger.error(ex);                
                }                
            }
        
            sqmle = null;
            try {
                Thread.sleep(pollingFrequency * 1000);
            } catch (InterruptedException e) {
            }
        }
    }
    
    private static void setPollingFrequency(Properties props) {
        String s = props.getProperty(SqmConfigParam.POLLING_FREQUENCY.getName());
        
        if (s != null) {
            try {
                pollingFrequency = Integer.parseInt(s);
            } catch (NumberFormatException ex) {
                logger.error("Error parsing polling_frequency value. Using default.");
            }
        } else {
            logger.error("polling_frequency not found in config file. Using default.");
        }
    }
    
    private static void setCalcCsf(Properties props) {
        String s = props.getProperty(SqmConfigParam.CALC_CSF.getName());
        
        if (s != null) {
            if (s.trim().equalsIgnoreCase("true") || s.trim().equalsIgnoreCase("yes")) {
                calcCsf = true;
            }
        } else {
            logger.error("calc_csf not found in config file. Using default.");
        }
    }
    
    private static void setArchiveToDb(Properties props) {
        String s = props.getProperty(SqmConfigParam.SAVE_TO_DB.getName());
        
        if (s != null) {
            if (s.trim().equalsIgnoreCase("true") || s.trim().equalsIgnoreCase("yes")) {
                archiveToDb = true;
            }
        } else {
            logger.error("save_to_db not found in config file. Defaulting to false");
        }
        
    }
}
